
#if 1

#include <stdint.h>
#include <string.h>
#include "contactless.h"
#include "WCI.h"
#include "ISO14443Command.h"
#include "Card.h"
#include "CardPrivate.h"
#include "ISO14443p3b.h"

static int TypeB_CheckATQB(const unsigned char atqb[], unsigned int alen) {
	if (atqb[0] != 0x50) {
		return 0;
	}
	if (alen < 12 || alen > 13) {
		return 0;
	}
	return 1;
}

static int TypeB_Probe(WCI* wci, uint8_t param, uint8_t n, ISO14443BInfo_T* info) {
	unsigned char tx[3] = { 0x05, 0x00, 0x00 };
	int ret;
	unsigned int alen = 0;
	unsigned char* atqb = info->atqb;

	tx[2] = param | (n & 7);

	ret = WCI_Exchange(wci, tx, sizeof(tx), atqb, &alen, 13, WaitTime_Ms(6, 0), FGT_B);
	if (ret) {
		return ret;
	}
	if (TypeB_CheckATQB(atqb, alen)) {
		info->len = (unsigned char)alen;
		return ret;
	}
	return CmdS_Invalid;
}

static int TypeB_Request(WCI* wci, unsigned char n, unsigned char atqb[], unsigned int* alen) {
	unsigned char tx[3] = { 0x05, 0x00, 0x00 };
	int ret;

	tx[2] |= n & 7;
	ret = WCI_Exchange(wci, tx, sizeof(tx), atqb, alen, 13, WaitTime_Ms(4, 0), FGT_B);
	if (ret) {
		return ret;
	}
	if (TypeB_CheckATQB(atqb, *alen)) {
		return ret;
	}
	return CmdS_Invalid;
}

static int TypeB_Wakeup(WCI* wci, unsigned char n, unsigned char atqb[], unsigned int* alen) {
	unsigned char tx[3] = { 0x05, 0x08, 0x00 };
	int ret;

	tx[2] |= n & 7;
	ret = WCI_Exchange(wci, tx, sizeof(tx), atqb, alen, 13, WaitTime_Ms(4, 0), FGT_B);
	if (ret) {
		return ret;
	}
	if (TypeB_CheckATQB(atqb, *alen)) {
		return ret;
	}
	return CmdS_Invalid;
}

static int TypeB_Halt(WCI* wci, const unsigned char pupi[4]) {
	unsigned char tx[5];
	unsigned char rx;
	unsigned int rlen = 0;
	int ret;

	tx[0] = 0x50;
	memcpy(tx + 1, pupi, 4);
	ret = WCI_Exchange(wci, tx, sizeof(tx), &rx, &rlen, 1, WaitTime_Ms(4, 0), FGT_B);
	if (ret) {
		return ret;
	}
	if (rx != 0) {
		ret = CmdS_Invalid;
	}
	return ret;
}

static int TypeB_CheckATTRIBResp(unsigned char cid, unsigned char resp[], unsigned int rlen) {
	unsigned char rcid;
	if (rlen == 0) {
		return 0;
	}
	rcid = resp[0] & 0x0F;
	if (cid == rcid) {
		return 1;
	}
	return rcid == 0;
}

int ISO14443B_ATTRIB(WCI* wci, const unsigned char pupi[4], unsigned char cid, unsigned char resp[], unsigned int *rlen) {
	unsigned char tx[9];
	int ret;

	tx[0] = 0x1D;
	memcpy(tx + 1, pupi, 4);
	tx[5] = 0x00;  // EOF/SOF required, default TR0/TR1
	tx[6] = 0x08;  //01--24 8--256
	tx[7] = 0x01;  //COMPATIBLE WITH 14443-4
	tx[8] = cid & 0x0F;  //CID
	ret = WCI_Exchange(wci, tx, 9, resp, rlen, 32, WaitTime_Ms(5, 0), FGT_B);
	if (ret) {
		return ret;
	}
	if (TypeB_CheckATTRIBResp(cid, resp, *rlen)) {
		return ret;
	}
	return CmdS_Invalid;
}

static int TypeB_SlotMarker(WCI* wci, unsigned char n, ISO14443BInfo_T* info) {
	unsigned char tx[1] = { 0x05 };
	int ret;
	unsigned int alen;
	unsigned char *atqb = info->atqb;

	tx[0] |= n << 4;
	ret = WCI_Exchange(wci, tx, sizeof(tx), atqb, &alen, 13, WaitTime_Ms(4, 0), FGT_B);
	if (ret) {
		return ret;
	}
	if (TypeB_CheckATQB(atqb, alen)) {
		return ret;
	}
	info->len = (unsigned char)alen;
	return CmdS_Invalid;
}

int ISO14443B_RequsetB(WCI* wci, ISO14443BInfo_T* info) {
	return TypeB_Probe(wci, 0x00, 0, info);
}

int ISO14443B_HaltB(WCI * wci, unsigned char pupi[4])
{
	return TypeB_Halt(wci, pupi);
}

int ISO14443B_WakeupB(WCI* wci, ISO14443BInfo_T* info) {
	return TypeB_Probe(wci, 0x08, 0, info);
}

void ISO14443B_SetMode(WCI* wci) {
	WCI_SetMode(wci, WCI_Mode_B);
}



static int TypeB_Scan(WCI* wci, unsigned char n, ISO14443BInfo_T* info) {
	int ret;
	unsigned int i;
	unsigned int present;
	unsigned int num;

	ret = TypeB_Probe(wci, 0x00, 0, info);
	if (ret == WCI_S_OK) {
		return ret;
	}
	present = 0;
	num = 1u << n;
	for (i = 1; i < num; i++) {
		ret = TypeB_SlotMarker(wci, (unsigned char)i, info);
		if (ret == WCI_S_OK) {
			return ret;
		}
		if (ret != WCI_S_Timeout) {
			present = 1;
		}
	}
	if (present != 0) {
		ret = WCI_S_Coll;
	}
	return ret;
}

static int TypeB_AntiLoop(WCI* wci, ISO14443BInfo_T* info) {
	unsigned char n;
	unsigned int i;
	int ret;

	for (i = 0, n = 2; i < 3; i++, n++) {
		ret = TypeB_Scan(wci, n, info);
		if (ret != WCI_S_Coll) { //Ok or NOT present
			return ret;
		}
	}
	//still coll,more scan
	for (i = 0; i < 3; i++) {
		ret = TypeB_Scan(wci, 4, info);
		if (ret != WCI_S_Coll) { //Ok or NOT present
			return ret;
		}
	}
	return ret;
}

int ISO14443B_Activate(WCI* wci, unsigned char req, ISO14443BInfo_T* info) {
	int ret;

	ISO14443B_SetMode(wci);
	if (req == PICC_Op_Request) {
		ret = ISO14443B_RequsetB(wci, info);
	}
	else {
		ret = ISO14443B_WakeupB(wci, info);
	}
	if (ret == WCI_S_Timeout) {
		return ret;
	}
	if (ret != WCI_S_OK) {
		ret = TypeB_AntiLoop(wci, info);
	}

	return ret;
}
#endif 

#if 0
int ISO14443B_Attrib(Card_T* card) {
	ISO14443BInfo_T* info = (ISO14443BInfo_T*)card->pdata;
	unsigned char* pupi = &info->atqb[1];
	unsigned char resp[16];
	unsigned int rlen;

	return ISO14443B_ATTRIB(card->wci, pupi, 0, resp, &rlen);
}
#endif 

